package com.ruoyi.heytalk.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.annotation.DataSource;
import com.ruoyi.common.constant.heytalk.CommonConstants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.heytalk.ImFriend;
import com.ruoyi.common.core.domain.heytalk.ImGroup;
import com.ruoyi.common.core.domain.heytalk.ImGroupUser;
import com.ruoyi.common.core.domain.heytalk.ImUser;
import com.ruoyi.common.core.domain.heytalk.dto.RecallChatDTO;
import com.ruoyi.common.core.domain.heytalk.dto.SendChatDTO;
import com.ruoyi.common.core.domain.heytalk.netty.ChatMsg;
import com.ruoyi.common.core.domain.heytalk.netty.DataType;
import com.ruoyi.common.core.domain.heytalk.netty.UserChannelUtils;
import com.ruoyi.common.core.domain.heytalk.vo.LoginImUser;
import com.ruoyi.common.core.service.HeyTalkTokenService;
import com.ruoyi.common.enums.DataSourceType;
import com.ruoyi.common.utils.JsonUtils;
import com.ruoyi.common.utils.RedisUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.heytalk.ByteBufUtils;
import com.ruoyi.heytalk.netty.IChatForwardHandlerService;
import com.ruoyi.heytalk.service.*;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zhusy
 * @since 2021/12/5
 */
@Slf4j
@Service
@DataSource(value = DataSourceType.SLAVE)
public class ChatServiceImpl implements ChatService {

    @Resource
    private HeyTalkTokenService tokenService;

    @Resource
    private IImFriendService friendService;

    @Resource
    private IImUserService userService;

    @Resource
    private IImGroupService groupService;

    @Resource
    private IImGroupUserService groupUserService;

    @Resource
    private IChatForwardHandlerService chatForwardHandlerService;

    @Override
    public AjaxResult<Object> sendChat(SendChatDTO sendChatDTO) {
        try {
            LoginImUser loginImUser = tokenService.getLoginImUser(ServletUtils.getRequest());
            ImUser fromUser = loginImUser.getUser();
            if (CommonConstants.ChatTypeEnum.SINGLE_CHAT.getCode().equals(sendChatDTO.getChatType())) {
                ImFriend friend = friendService.getOne(new LambdaQueryWrapper<ImFriend>()
                        .eq(ImFriend::getUserId, sendChatDTO.getToId())
                        .eq(ImFriend::getFriendId, loginImUser.getUserId())
                        .eq(ImFriend::getIsBlack, CommonConstants.IsBlackEnum.ZERO.getCode()));
                if (Objects.isNull(friend)) {
                    return AjaxResult.error("对方不存在或者已经把你拉黑", null);
                }
                //朋友用户对象
                ImUser friendUser = userService.getById(friend.getUserId());
                if (Objects.isNull(friendUser) || CommonConstants.UserStatusEnum.NORMAL.getCode().equals(friendUser.getStatus())) {
                    return AjaxResult.error("对方已被禁用", null);
                }
                ChatMsg chatMsg = ChatMsg.builder()
                        .id(IdUtil.fastSimpleUUID())
                        .fromAvatar(fromUser.getAvatar())
                        .fromId(loginImUser.getUserId())
                        .fromName(StrUtil.isNotBlank(fromUser.getNickName())? fromUser.getNickName() : fromUser.getUserName())
                        .toId(friendUser.getId())
                        .toName(StrUtil.isNotBlank(friendUser.getNickName())? friendUser.getNickName() : friendUser.getUserName())
                        .toAvatar(friendUser.getAvatar())
                        .chatType(CommonConstants.ChatTypeEnum.SINGLE_CHAT.getCode())
                        .type(sendChatDTO.getType())
                        .data(sendChatDTO.getData())
                        .isRemove(CommonConstants.IsRemoveEnum.ZERO.getCode())
                        .build();
                //视频，截取封面
                if (CommonConstants.ChatMsgTypeEnum.VIDEO.getCode().equals(chatMsg.getType())) {
                    chatMsg.setOptions(JsonUtils.parseObject(sendChatDTO.getOptions(), Object.class));
                }
                //音频，带上音频时长
                if (CommonConstants.ChatMsgTypeEnum.AUDIO.getCode().equals(chatMsg.getType())) {
                    ChatMsg.AudioOptions audioOptions = JsonUtils.parseObject(sendChatDTO.getOptions(), ChatMsg.AudioOptions.class);
                    chatMsg.setOptions(ChatMsg.AudioOptions.builder().time(audioOptions.getTime()).build());
                }
                //名片
                if (CommonConstants.ChatMsgTypeEnum.CARD.getCode().equals(chatMsg.getType())) {
                    chatMsg.setOptions(JsonUtils.parseObject(sendChatDTO.getOptions(), ChatMsg.CardOptions.class));
                }
                List<String> userList = new ArrayList<>();
                userList.add(friendUser.getId());
                chatForwardHandlerService.chat(userList, CommonConstants.ChatTypeEnum.SINGLE_CHAT.getCode(), true, true, chatMsg);
                return AjaxResult.success(chatMsg);
            } else if (CommonConstants.ChatTypeEnum.GROUP_CHAT.getCode().equals(sendChatDTO.getChatType())) {
                ImGroup imGroup = groupService.getOne(new LambdaQueryWrapper<ImGroup>()
                        .eq(ImGroup::getStatus, CommonConstants.UserStatusEnum.DEACTIVATE.getCode())
                        .eq(ImGroup::getId, sendChatDTO.getToId()));
                if (Objects.isNull(imGroup)) {
                    return AjaxResult.error("该群聊不存在或者已被封禁", null);
                }
                List<ImGroupUser> imGroupUserList = groupUserService.list(new LambdaQueryWrapper<ImGroupUser>().eq(ImGroupUser::getGroupId, imGroup.getId()));
                //查找发送者在群内的信息
                ImGroupUser groupUser = imGroupUserList.stream().filter(imGroupUser -> imGroupUser.getUserId().equals(loginImUser.getUserId()))
                        .findFirst().orElse(imGroupUserList.isEmpty()? null : imGroupUserList.get(imGroupUserList.size() - 1));
                if (Objects.isNull(groupUser)) {
                    return AjaxResult.error("你不是该群的成员", null);
                }
                //发送的消息中排除自己
                imGroupUserList.remove(groupUser);
                ChatMsg chatMsg = ChatMsg.builder()
                        .id(IdUtil.fastSimpleUUID())
                        .fromAvatar(fromUser.getAvatar())
                        .fromId(loginImUser.getUserId())
                        .fromName(StrUtil.isNotBlank(groupUser.getNickName())? groupUser.getNickName() : StrUtil.isNotBlank(fromUser.getNickName()) ? fromUser.getNickName() : fromUser.getUserName())
                        .toId(imGroup.getId())     //群ID
                        .toName(imGroup.getName())   //群名称
                        .toAvatar(imGroup.getAvatar())
                        .chatType(CommonConstants.ChatTypeEnum.GROUP_CHAT.getCode())
                        .type(sendChatDTO.getType())
                        .data(sendChatDTO.getData())
                        .isRemove(CommonConstants.IsRemoveEnum.ZERO.getCode())
                        .group(imGroup)
                        .build();
                //视频，截取封面
                if (CommonConstants.ChatMsgTypeEnum.VIDEO.getCode().equals(chatMsg.getType())) {
                    chatMsg.setOptions(JsonUtils.parseObject(sendChatDTO.getOptions(), Object.class));
                }
                //音频，带上音频时长
                if (CommonConstants.ChatMsgTypeEnum.AUDIO.getCode().equals(chatMsg.getType())) {
                    ChatMsg.AudioOptions audioOptions = JsonUtils.parseObject(sendChatDTO.getOptions(), ChatMsg.AudioOptions.class);
                    chatMsg.setOptions(ChatMsg.AudioOptions.builder().time(audioOptions.getTime()).build());
                }
                //名片
                if (CommonConstants.ChatMsgTypeEnum.CARD.getCode().equals(chatMsg.getType())) {
                    chatMsg.setOptions(JsonUtils.parseObject(sendChatDTO.getOptions(), ChatMsg.CardOptions.class));
                }
                List<String> userIdList = imGroupUserList.stream().map(ImGroupUser::getUserId).collect(Collectors.toList());
                chatForwardHandlerService.chat(userIdList, CommonConstants.ChatTypeEnum.GROUP_CHAT.getCode(), true, true, chatMsg);
                return AjaxResult.success(chatMsg);
            }
            return AjaxResult.error("传递非法的消息类型", null);
        } catch (Exception e) {
            log.error("错误信息e:{}", e);
            return AjaxResult.error("发送消息失败", null);
        }
    }

    @Override
    @Transactional
    public AjaxResult<Void> getMessage() {
        try {
            LoginImUser loginImUser = tokenService.getLoginImUser(ServletUtils.getRequest());
            //todo 这种通过keys的方式获取朋友说有性能问题，后面再考虑
            Collection<String> keys = RedisUtils.keys(CommonConstants.CHAT_MESSAGE + loginImUser.getUserId()  + CommonConstants.PLUS + "*");
            log.info("redis的key值:{}", keys);
            List<DataType> dataTypeList = new ArrayList<>();
            keys.stream().forEach(key -> {
                DataType dataType = RedisUtils.getCacheObject(key);
                if (!Objects.isNull(dataType)) {
                    dataTypeList.add(dataType);
                }
                RedisUtils.deleteObject(key);
            });
            if (!Objects.isNull(dataTypeList) && !dataTypeList.isEmpty()) {
                dataTypeList.stream().sorted(Comparator.comparing(DataType::getCreateTime)).collect(Collectors.toList())
                        .stream().forEach(dataType -> {
                            if (!Objects.isNull(dataType)) {
                                Channel channel = UserChannelUtils.getChannel(loginImUser.getUserId());
                                //接收方不存在或socket不在线
                                if (!Objects.isNull(channel) && UserChannelUtils.hasLogin(channel)) {
                                    channel.writeAndFlush(ByteBufUtils.getByteBuf(dataType));
                                } else {
                                    //保存在缓存中,但是获取离线消息情况下还不在线的概率很小
                                    RedisUtils.setCacheObject(CommonConstants.CHAT_MESSAGE + loginImUser.getUserId() + CommonConstants.PLUS + IdUtil.fastSimpleUUID(), dataType);
                                }
                            }
                });
            }
            return AjaxResult.success();
        } catch (Exception e) {
            log.error("获取离线消息并转发发生了异常:{}", e);
            return AjaxResult.error();
        }
    }

    @Override
    public AjaxResult<Object> recallChat(RecallChatDTO recallChatDTO) {
        try {
            LoginImUser loginImUser = tokenService.getLoginImUser(ServletUtils.getRequest());
            if (CommonConstants.ChatTypeEnum.SINGLE_CHAT.getCode().equals(recallChatDTO.getChatType())) {
                ChatMsg chatMsg = ChatMsg.builder()
                        .id(recallChatDTO.getId())
                        .fromId(loginImUser.getUserId())
                        .toId(recallChatDTO.getToId())
                        .chatType(CommonConstants.ChatTypeEnum.SINGLE_CHAT.getCode())
                        .build();
                List<String> userIdList = new ArrayList<>();
                userIdList.add(recallChatDTO.getToId());
                chatForwardHandlerService.chat(userIdList, CommonConstants.DataTypeEnum.RECALL.getCode(), true, false, chatMsg);
                return AjaxResult.success(chatMsg);
            } else if (CommonConstants.ChatTypeEnum.GROUP_CHAT.getCode().equals(recallChatDTO.getChatType())) {
                ImGroup imGroup = groupService.getOne(new LambdaQueryWrapper<ImGroup>()
                        .eq(ImGroup::getStatus, CommonConstants.UserStatusEnum.DEACTIVATE.getCode())
                        .eq(ImGroup::getId, recallChatDTO.getToId()));
                if (Objects.isNull(imGroup)) {
                    return AjaxResult.error("该群聊不存在或者已被封禁", null);
                }
                List<ImGroupUser> imGroupUserList = groupUserService.list(new LambdaQueryWrapper<ImGroupUser>().eq(ImGroupUser::getGroupId, imGroup.getId()));
                //查找发送者在群内的信息
                ImGroupUser groupUser = imGroupUserList.stream().filter(imGroupUser -> imGroupUser.getUserId().equals(loginImUser.getUserId()))
                        .findFirst().orElse(imGroupUserList.isEmpty()? null : imGroupUserList.get(imGroupUserList.size() - 1));
                if (Objects.isNull(groupUser)) {
                    return AjaxResult.error("你不是该群的成员", null);
                }
                //发送的消息中排除自己
                imGroupUserList.remove(groupUser);
                ChatMsg chatMsg = ChatMsg.builder()
                        .id(recallChatDTO.getId())
                        .fromId(loginImUser.getUserId())
                        .toId(imGroup.getId())     //群ID
                        .chatType(CommonConstants.ChatTypeEnum.GROUP_CHAT.getCode())
                        .build();
                List<String> userIdList = imGroupUserList.stream().map(ImGroupUser::getUserId).collect(Collectors.toList());
                chatForwardHandlerService.chat(userIdList, CommonConstants.DataTypeEnum.RECALL.getCode(), true, false, chatMsg);
                return AjaxResult.success(chatMsg);
            }
            return AjaxResult.error("传递非法的消息类型", null);
        } catch (Exception e) {
            log.error("错误信息e:{}", e);
            return AjaxResult.error("撤回消息失败", null);
        }
    }

}
